#include "textureManager.h"

/****************************************************//**
 * Project-Namespace
 ********************************************************/
namespace jae
{

/****************************************************//**
 * Constructor of the class.
 ********************************************************/
TextureManager::TextureManager(QGLWidget* aSharedGLContext)
{
    _textureList.clear();
    _pSharedGLContext = aSharedGLContext;
}

/****************************************************//**
 * Destructor of the class.
 ********************************************************/
TextureManager::~TextureManager()
{   
    //Loesche alle Texturen aus Grafikspeicher
    _pSharedGLContext->makeCurrent();
    std::list<ListElem>::iterator iter;

    for (iter = _textureList.begin(); iter != _textureList.end(); iter++)
    {
        glDeleteTextures(1, &iter->_textureIndex);

        if (iter->_pTextureFileName != NULL)
        {
            delete[] iter->_pTextureFileName;
            iter->_pTextureFileName = NULL;
        }
    }
    //Loesche Liste
    _textureList.clear();
}

/****************************************************//**
 * Loads an Texture from file if it's not yet loaded. If it
 * is already loaded it returns the index of the existing 
 * textur.
 * @return returns the Index of the texture.
 ********************************************************/
GLuint TextureManager::addElem(const char* aFileName)
{
    if ((aFileName == NULL) || (strlen(aFileName) == 0))
    {

        Logger logger;
        logger.error("ERROR",
                "GLuint TextureManager::addElem(const char* aFileName)",
                "Can't load texture. Filename is NULL or empty (\"\")!");
        return 0;
    }

    GLuint tmpIndex = duplicateCheck(aFileName);

    if (tmpIndex > 0) //textur allready loaded
        return tmpIndex;
    else
    {
        _pSharedGLContext->makeCurrent();
        
        //Generiere Texturen Index
        glGenTextures(1, &tmpIndex);
        
        //Fuege Textur ein:
        glBindTexture(GL_TEXTURE_2D, tmpIndex);

        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
        
        //Loading Image from file
        QImage imageFile;
        if (!imageFile.load(aFileName))
        {
            Logger logger;
            logger.error("ERROR",
                    "GLuint TextureManager::addElem(const char* aFileName)",
                    "Can't load texture. File does not exist? / Unknown Fileformat?");
            logger.write("  aFilename: '");
            logger.write(aFileName);
            logger.write("'\n");
            return 0;
        }
        imageFile = QGLWidget::convertToGLFormat(imageFile);

        gluBuild2DMipmaps(GL_TEXTURE_2D, 3, imageFile.width(), imageFile.height(), GL_RGBA, GL_UNSIGNED_BYTE, imageFile.bits());
     
        //create Listelem
        ListElem listElem;
        listElem._textureIndex = tmpIndex;
        
        int fileNameLength = strlen(aFileName) + 1; //+1 because of '\0' at the end
        listElem._pTextureFileName = new char[fileNameLength]; 
        memcpy (listElem._pTextureFileName, aFileName, fileNameLength);

        //Fuege Listenelement hinzu
        _textureList.push_front(listElem);
        
        return tmpIndex;
    }
}

/****************************************************//**
 * Returns true if there is no texture loaded, else false.
 ********************************************************/
bool TextureManager::isEmpty(void)
{
    return _textureList.empty();
}

/****************************************************//**
 * Removes an texture from memory.
 ********************************************************/
void TextureManager::delElem(GLuint index)
{
    std::list<ListElem>::iterator iter;
    std::list<ListElem>::iterator delElem;
    bool textureFound = false;

    for (iter = _textureList.begin(); iter != _textureList.end(); iter++)
    {
        if (iter->_textureIndex == index)
        {
            _pSharedGLContext->makeCurrent();
            glDeleteTextures(1, &iter->_textureIndex);

            if (iter->_pTextureFileName != NULL)
            {
                delete[] iter->_pTextureFileName;
                iter->_pTextureFileName = NULL;
            }

            delElem = iter;
            textureFound = true;
        }
    }

    //removes founded Element from list
    if (textureFound)
        _textureList.erase(delElem);
}

/****************************************************//**
 * Return true if the filename of a texture is already loaded.
 ********************************************************/
GLuint TextureManager::duplicateCheck(const char *aFileName)
{
    std::list<ListElem>::iterator iter;

    for (iter = _textureList.begin(); iter != _textureList.end(); iter++)
    {
        if (strcmp(aFileName, iter->_pTextureFileName) == 0)
            return iter->_textureIndex;
    }

    //Texture not found
    return 0;
}

/****************************************************//**
 * Lists all loaded textures of an TextureManager
 ********************************************************/
void TextureManager::writeToLog()
{
    Logger logger;
    if (this->isEmpty())
        logger.write("  Der TextureManager enthaelt KEINE Texturen!\n");
    else
    {
        logger.write("  Der TextureManager enthaelt folgende Texturen:\n");
        std::list<TextureManager::ListElem>::iterator iter;

        for (iter = _textureList.begin(); iter != _textureList.end(); iter++)
        {
            logger.write("    ");
            logger.write(iter->_textureIndex);
            logger.write(" : ");
            logger.write(iter->_pTextureFileName);
            logger.write("\n");
        }
    }
}

}//Namespace
